/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pobicos;

import java.awt.Event;
import java.awt.Graphics;
import org.xml.sax.helpers.DefaultHandler;
import java.io.Writer;
import java.io.PrintWriter;
import java.io.BufferedWriter;
import java.io.FileWriter;

import java.awt.Paint;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.geom.Point2D;
import java.awt.event.ActionListener;
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
import java.awt.event.ActionEvent;

import java.util.Collection;
import java.util.HashSet;
import java.util.ArrayList;
import java.util.Set;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.AbstractAction;

import org.apache.commons.collections15.Factory;
import org.apache.commons.collections15.Transformer;
import org.apache.commons.collections15.functors.ConstantTransformer;

import edu.uci.ics.jung.algorithms.layout.GraphElementAccessor;
import edu.uci.ics.jung.algorithms.layout.TreeLayout;
//import edu.uci.ics.jung.algorithms.layout.RadialTreeLayout;
import edu.uci.ics.jung.graph.util.EdgeType;
import edu.uci.ics.jung.graph.DirectedGraph;
import edu.uci.ics.jung.graph.DirectedSparseMultigraph;
import edu.uci.ics.jung.graph.Forest;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.DelegateTree;
import edu.uci.ics.jung.graph.DelegateForest;
import edu.uci.ics.jung.graph.DirectedSparseGraph;
import edu.uci.ics.jung.graph.SparseGraph;
import edu.uci.ics.jung.graph.SparseMultigraph;
import edu.uci.ics.jung.graph.Tree;
import edu.uci.ics.jung.visualization.GraphZoomScrollPane;
import edu.uci.ics.jung.visualization.VisualizationServer;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.control.CrossoverScalingControl;
import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
import edu.uci.ics.jung.visualization.control.AbstractPopupGraphMousePlugin;
import edu.uci.ics.jung.visualization.control.ModalGraphMouse;
import edu.uci.ics.jung.visualization.control.ScalingControl;
import edu.uci.ics.jung.visualization.decorators.EdgeShape;
import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;

import edu.uci.ics.jung.io.GraphMLWriter;
import edu.uci.ics.jung.io.GraphMLReader;
import java.io.IOException;
import javax.swing.JTextField;
import javax.xml.parsers.ParserConfigurationException;

import edu.uci.ics.jung.graph.util.TreeUtils;
import edu.uci.ics.jung.visualization.LayeredIcon;
import edu.uci.ics.jung.visualization.decorators.DefaultVertexIconTransformer;
import edu.uci.ics.jung.visualization.decorators.EllipseVertexShapeTransformer;
import edu.uci.ics.jung.visualization.picking.PickedState;
import edu.uci.ics.jung.visualization.renderers.Checkmark;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Shape;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.security.SecureClassLoader;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.AbstractButton;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.plaf.IconUIResource;
import edu.uci.ics.jung.visualization.renderers.Renderer;
import java.text.DecimalFormat;

/**
 *
 * @author marcin
 * 
 */
@SuppressWarnings("serial")
public class JungTreePanel {
    /**
     * 
     */
    private JPanel treeJPanel;
    /**
     * the graph
     */
    private Forest<Integer, Integer> graph;
    /**
     * 
     */
    private Integer nodeCounter_ = 0;
    /**
     * 
     */
    private Integer dimX_ = 0;
    /**
     * 
     */
    private Integer dimY_ = 0;
    /**
     * 
     */
    private Factory<Integer> edgeFactory;
    /**
     * 
     */
    private Factory<Integer> vertexFactory;
    /**
     * the visual component and renderer for the graph
     */
    private VisualizationViewer<Integer, Integer> vv;
    /**
     *  layout of composed graph - tree
     */
    private TreeLayout<Integer, Integer> layout;
    /**
     * 
     */
    private JFrame mainAppFrame_;;
    /**
     * 
     */
    private MyTree<Agent> logicalTree_;
    /**
     * 
     */
    private Collection deselectedCollection_;
    private Collection typeAssaingedCollection_;
    private Collection multipleNodeCollection_;
    private Collection subGraphCollection;
    /**
     * 
     */
    private PickedState<Integer> picked_state;
    
    
    private GraphZoomScrollPane graphPanel;
    
    private BufferedImage tempImage;
    
    private BufferedImage redImageIcon;
    private BufferedImage yellowImageIcon;
    private BufferedImage greenImageIcon;
    private BufferedImage greenImageIconM;
    private BufferedImage orangeImageIcon;
    private BufferedImage orangeImageIconM;
    
    public MyDefaultVertexIconTransformer vertexIconFunction;
    public Integer currentPickedVertex = 0;


    @SuppressWarnings("unchecked")
    public JungTreePanel(AdaptSysView view) {
        mainAppFrame_ = view.getFrame();
        treeJPanel = new JPanel(new BorderLayout());
        // create a simple graph for the demo
        graph = new DelegateTree<Integer, Integer>();
        logicalTree_ = new MyTree<Agent>();
        /**
         * Collection for nodes
         */
        deselectedCollection_ = new ArrayList();
        typeAssaingedCollection_ = new ArrayList();
        multipleNodeCollection_ = new ArrayList();
        subGraphCollection = new ArrayList();        
    }

    public void setUpTheTree(int dimX, int dimY) {

        dimX_ = dimX;
        dimY_ = dimY;
        createTreeRoot();

        layout = new TreeLayout<Integer, Integer>(graph, 70, 80);

        vv = new VisualizationViewer<Integer, Integer>(layout, new Dimension(dimX_, dimY_)) {
            
            
//            @Override
//            public void paint(Graphics g) {
//                super.paint(g);
//                int borderSize = 15;
//                for (Integer s : layout.getGraph().getVertices()) {
//                    Point2D d = new Point2D.Double(layout.transform(s).getX(), layout.transform(s).getY());
//                    g.setColor(Color.BLACK);
//                    g.drawRect((int) d.getX() + borderSize, (int) d.getY() - borderSize, borderSize, borderSize);
//                    g.setColor(Color.CYAN);
//                    g.fillRect((int) d.getX() + borderSize + 1, (int) d.getY() - (borderSize - 1), borderSize - 1, borderSize - 1);
//                }
//            }
            
        };
        
         vertexIconFunction = new MyDefaultVertexIconTransformer<Integer>();
       // vertexIconFunction.setIconMap(iconMap);
        vv.getRenderContext().setVertexIconTransformer(vertexIconFunction);
     //   vv.getPickedVertexState().addItemListener(new PickWithIconListener(vertexIconFunction));
        vv.getRenderer().getVertexLabelRenderer().setPosition(Renderer.VertexLabel.Position.E);   
        picked_state = vv.getPickedVertexState();
        vv.setBackground(Color.white);
        vv.getRenderContext().setEdgeShapeTransformer(new EdgeShape.Line());
        vv.getRenderContext().setVertexLabelTransformer(new ToStringLabeller());
        vv.getRenderContext().setVertexFillPaintTransformer(new MyVertexFillPaintFunction<Integer>());
        vv.setVertexToolTipTransformer(new ToStringLabeller());
        vv.setVertexToolTipTransformer(new VertexTips<Integer>());
        vv.getRenderContext().setArrowFillPaintTransformer(new ConstantTransformer(Color.lightGray));
        vv.getRenderContext().setVertexShapeTransformer(new ClusterVertexShapeFunction());
     
    /////////////////////////////////////////////////////////////

//        for (int i = 5; i < 7; i++) {
//            try {
//                BufferedImage img = null;
//                try {
//                    img = ImageIO.read(new File("redball.png"));
//
//                } catch (IOException e) {
//                }
//                Icon icon = new LayeredIcon(img.getScaledInstance(25, 25, Image.SCALE_SMOOTH));
//                //  Icon icon = new LayeredIcon(new BufferedImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR));
//                iconMap.put(i, icon);
//                ((LayeredIcon) icon).add(new LayeredIcon(tempImage.getScaledInstance(70, 70, Image.SCALE_SMOOTH)));
//
//            } catch (Exception ex) {
//            }
//        }
      
        graphPanel = new GraphZoomScrollPane(vv);

        treeJPanel.add(graphPanel);
        final DefaultModalGraphMouse graphMouse = new DefaultModalGraphMouse() {    
            @Override
            public void mousePressed(MouseEvent e) {
                super.mousePressed(e);
                Set<Integer> s = picked_state.getPicked();
                /**
                 * Handle avaliable buttons for selected node
                 */
                if (s.size() == 1 && AdaptSysView.AddTypeComboBox.isEnabled()) {
                    currentPickedVertex = (Integer) s.toArray()[0];
                    AdaptSysView.AssaignAgentTypeButton.setEnabled(true);
                    AdaptSysView.isMultipleCheckBox.setEnabled(true);
                    if (multipleNodeCollection_.contains(currentPickedVertex)) {
                        AdaptSysView.isMultipleCheckBox.setSelected(true);
                    } else {
                        AdaptSysView.isMultipleCheckBox.setSelected(false);
                    }
                } else {
                    AdaptSysView.AssaignAgentTypeButton.setEnabled(false);
                    AdaptSysView.isMultipleCheckBox.setEnabled(false);
                    AdaptSysView.isMultipleCheckBox.setSelected(false);
                    AdaptSysView.openSubtreeNodeEditorButton.setEnabled(false);
                    AdaptSysView.openClickHappinessButton.setEnabled(false);
                }
                /**
                 * Handle subtree completetion
                 */
                if (s.size() == 1) {
                    AdaptSysView.openSubtreeNodeEditorButton.setEnabled(false);
                    AdaptSysView.openClickHappinessButton.setEnabled(false);
                    currentPickedVertex = (Integer) s.toArray()[0];
                    MyNode<Agent> tempPickedNode = logicalTree_.getNodeAt(currentPickedVertex);
                    //check if current picked agent has type assaigned
                    if (tempPickedNode.getData().getType() != null) {
                        //check if current picked agent has childeren
                        if (tempPickedNode.getNumberOfChildren() != 0) {
                            //check if subtree of picked vertex has types assaigned
                            for (MyNode<Agent> m : tempPickedNode.getChildren()) {
                                if (m.getData().getType() == null) {
                                 //   AdaptSysView.openSubtreeNodeEditorButton.setEnabled(false);
                                    return;
                                } else {
                                    subGraphCollection = graph.getChildren(currentPickedVertex);
                                    AdaptSysView.openSubtreeNodeEditorButton.setEnabled(true);
                                }
                            }
                        }
                    }
                }
                if (s.size() == 1) {
                    currentPickedVertex = (Integer) s.toArray()[0];
                    MyNode<Agent> tempPickedNode = logicalTree_.getNodeAt(currentPickedVertex);
                    if(tempPickedNode.getNumberOfChildren()==0) {
                        AdaptSysView.openClickHappinessButton.setEnabled(true);
                    }             
                }
                //MUST BE HERE!!!!!!!!!!!!!!!!!!!!!
                // super.mousePressed(e);
            }
            
        };
        ///////////////////////////////////////
        vv.setGraphMouse(graphMouse);
        /**
         * Adding plugin for nodes selection/deselection
         */
        graphMouse.add(new PopupGraphMousePlugin());

        JComboBox modeBox = graphMouse.getModeComboBox();
        modeBox.addItemListener(graphMouse.getModeListener());
        graphMouse.setMode(ModalGraphMouse.Mode.PICKING);

        final ScalingControl scaler = new CrossoverScalingControl();

        JButton plus = new JButton("+");
        plus.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                scaler.scale(vv, 1.1f, vv.getCenter());
            }
        });
        JButton minus = new JButton("-");
        minus.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                scaler.scale(vv, 1 / 1.1f, vv.getCenter());
            }
        });
        final JTextField ParentNodeTextFiled = new JTextField("0", 4);

        JButton addNodeButton = new JButton("Add Agent");
        addNodeButton.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                try {
                    Integer n = Integer.parseInt(ParentNodeTextFiled.getText());
                    if (graph.containsVertex(n)) {
                        graph.addEdge(nodeCounter_, n, nodeCounter_, EdgeType.DIRECTED);
                        if (n != 0) {
                            logicalTree_.getNodeAt(n).addChild(new MyNode(new Agent(nodeCounter_)));
                        } else {
                            logicalTree_.getRootElement().addChild(new MyNode(new Agent(nodeCounter_)));
                        }
                        layout = new TreeLayout<Integer, Integer>(graph, 70, 80);
                        vv.setGraphLayout(layout);
                        vv.repaint();
                        nodeCounter_++;
                    }
                } catch (NumberFormatException w) {
                    JOptionPane.showMessageDialog(null, "Incorrect number format!");
                    ParentNodeTextFiled.setText("0");
                }
            }
        });

        JButton deleteNodeButton = new JButton("Delete");
        deleteNodeButton.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                Collection picked = new HashSet(vv.getPickedVertexState().getPicked());
                if (picked.size() == 1) {
                    Object nodeToDelete = picked.iterator().next();

                    logicalTree_.getNodeAt(graph.getParent(currentPickedVertex)).getData().setOperatorsList(null);

                    graph.removeVertex(nodeToDelete.hashCode());
                    logicalTree_.deleteNode(currentPickedVertex);
                    vv.getPickedVertexState().clear();
                    //refresh layout
                    layout = new TreeLayout<Integer, Integer>(graph, 70, 80);
                    vv.setGraphLayout(layout);
                    vv.repaint();
                }
            }
        });
        JButton clearTreeButton = new JButton("Clear");
        clearTreeButton.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                nodeCounter_ = 0;
                /**
                 * Create everything from scratch
                 */
                graph = new DelegateTree<Integer, Integer>();
                logicalTree_ = new MyTree<Agent>();
                createTreeRoot();
                layout = new TreeLayout<Integer, Integer>(graph, 70, 80);
                /**
                 * Empty all vertex collection
                 */
                deselectedCollection_.clear();
                typeAssaingedCollection_.clear();
                multipleNodeCollection_.clear();
             //   allOperatorsList_.clear();
                
                vv.setGraphLayout(layout);
                vv.repaint();
                
//                Graphics2D g2d = (Graphics2D) (vv.getGraphics());
//                g2d.setColor(Color.red);
//                g2d.fillRect(50, 50, 100, 100);
//                g2d.drawRect(50, 50, 100, 100);
//                vv.paint(g2d);
                
            }
        });
        /**
         *  Adding control buttons to the control panel
         */
        JPanel scaleGrid = new JPanel(new GridLayout(1, 5));
        scaleGrid.setBorder(BorderFactory.createTitledBorder("ControlPanel"));

        JPanel controls = new JPanel();

        scaleGrid.add(addNodeButton);
        scaleGrid.add(ParentNodeTextFiled);
        scaleGrid.add(deleteNodeButton);
        scaleGrid.add(clearTreeButton);
        scaleGrid.add(modeBox);
        //   scaleGrid.add(plus);
        //    scaleGrid.add(minus);
        controls.add(scaleGrid);
        //      controls.add(modeBox);
        treeJPanel.add(controls, BorderLayout.SOUTH);
        
   //     layout.DEFAULT_DISTY=60;
    //    layout.DEFAULT_DISTX=50;
        
    }
    /**
     * Create the root for the tree
     */
    private void createTreeRoot() {
                try {
            redImageIcon = ImageIO.read(new File("images/redball.png"));
            greenImageIcon = ImageIO.read(new File("images/greenball.png"));
             greenImageIconM = ImageIO.read(new File("images/greenballM.png"));
            yellowImageIcon = ImageIO.read(new File("images/yellowball.png"));
            orangeImageIcon = ImageIO.read(new File("images/orangeball.png"));
            orangeImageIconM = ImageIO.read(new File("images/orangeballM.png"));

        } catch (IOException e) {
        }
        graph.addVertex(nodeCounter_);
        logicalTree_.setRootElement(new MyNode(new Agent(nodeCounter_)));
        Icon icon = new LayeredIcon(redImageIcon.getScaledInstance(25, 25, Image.SCALE_SMOOTH));
        nodeCounter_++;

    }

    /**
     * 
     * @param filename - saved graph file name
     * @throws IOException 
     */
    public void saveToGraphmlFile(String filename) throws IOException {

        //
        GraphMLWriter<Integer, Integer> g = new GraphMLWriter<Integer, Integer>();
        //
        Writer out = new PrintWriter(new BufferedWriter(new FileWriter(filename)));
        //
        g.save((DirectedGraph) graph, out);
    }

    public void readFromGraphmlFile(String filename, final HashMap<Integer, Agent> agentsMap) throws ParserConfigurationException, org.xml.sax.SAXException, IOException {

        vertexFactory = new Factory<Integer>() {
            

            Object[] indexSet = null;
            int i = 0;

            public Integer create() {
                indexSet = agentsMap.keySet().toArray();
                return (Integer) indexSet[i++];
            }
        };
        edgeFactory = new Factory<Integer>() {

            int i = 0;

            public Integer create() {
                return i++;
            }
        };
        //not sure about that part
        logicalTree_ = new MyTree<Agent>();
        
        deselectedCollection_.clear();
        typeAssaingedCollection_.clear();
        multipleNodeCollection_.clear();
        
        logicalTree_.setRootElement(new MyNode(new Agent(agentsMap.get(0))));
          //
        GraphMLReader<DirectedGraph<Integer, Integer>, Integer, Integer> gmlr =
                new GraphMLReader<DirectedGraph<Integer, Integer>, Integer, Integer>(vertexFactory, edgeFactory);
        //
        final DirectedGraph<Integer, Integer> graphee = new DirectedSparseGraph<Integer, Integer>();
        //
        gmlr.load(filename, graphee);
        //
        DelegateForest<Integer, Integer> mTree = new DelegateForest<Integer, Integer>();
        /**
         *  DirectedGraph to DelegateForest
         */
        for (Integer n : graphee.getVertices()) {
            mTree.addVertex(n);
        }
        //if agent types has not been assaigned 
        if (agentsMap == null) {
            for (Integer e : graphee.getEdges()) {
                mTree.addEdge(e, graphee.getSource(e), graphee.getDest(e));
                logicalTree_.getNodeAt(graphee.getSource(e)).addChild(new MyNode(new Agent(graphee.getDest(e)))); 
                //assaign if multiple mode
                Agent tempAgent = (Agent) logicalTree_.getNodeAt(e).getData();
                if (tempAgent.isMultilpe()) {
                    multipleNodeCollection_.add(tempAgent.getId());
                }
            }
        } else {
            //edges need's to be sorted in a proper way - to pass to logicalTree.addChild(v) 
            List<Integer> tem = new ArrayList<Integer>();
            for (Integer i : graphee.getEdges()) {
                tem.add(i);
            }
            Comparator<Integer> t = new Comparator<Integer>() {

                public int compare(Integer o1, Integer o2) {

                    Integer c1 = graphee.getDest(o1);
                    Integer c2 = graphee.getDest(o2);
                    return c1.compareTo(c2);
                }
            };
            Collections.sort(tem, t);

            for (Integer e : tem) {
                //add edge to graphical tree
                mTree.addEdge(e, graphee.getSource(e), graphee.getDest(e));
                //add new agent to logical tree-make copy from loaded AgentsMap 
                Agent a = new Agent(agentsMap.get(graphee.getDest(e)));
                logicalTree_.getNodeAt(graphee.getSource(e)).addChild(new MyNode(a));
            }
            for (Integer i : graphee.getVertices()) {
                Agent tempAgent = (Agent) logicalTree_.getNodeAt(i).getData();
                if (tempAgent.getType() != null) {
                    typeAssaingedCollection_.add(tempAgent.getId());
                }
                if (tempAgent.isMultilpe()) {
                    multipleNodeCollection_.add(tempAgent.getId());
                }           
            }

        }

        nodeCounter_ = Collections.max(mTree.getVertices()) + 1;
        graph = mTree;
        layout = new TreeLayout<Integer, Integer>(mTree, 70, 80);
        vv.setGraphLayout(layout);        
        vv.repaint();
    }

    public JPanel getTreeJPanel() {
       return treeJPanel;
    }

    public MyTree getLogicalTree() {
        return logicalTree_;
    }

    public Collection getAssaingedVertexList() {
        return typeAssaingedCollection_;
    }

    public PickedState<Integer> getPickedState() {
        return picked_state;
    }

    public Collection getSubGraphCollection() {
        return subGraphCollection;
    }

    public JFrame getMainViewFrame() {
        return mainAppFrame_;
    }

    public Collection getMultipleNodeCollection() {
        return multipleNodeCollection_;
    }

    public Forest<Integer, Integer> getGraph() {
        return graph;
    }

    public void vvSetSize(int x, int y) {
        graphPanel.setSize(x, y);
        vv.repaint();
    }
    
    public void repaintVV() {
        vv.repaint();
    }

//    private Collection NodesToDeselect = new ArrayList();
//
//    public Collection deselectNodes(Integer v) {
//
//        for (Integer n : graph.getSuccessors(v)) {
//            NodesToDeselect.add((Integer) n);
//            deselectNodes(n);
//        }
//        return NodesToDeselect;
//    }
    /**
     * a GraphMousePlugin that offers popup
     * menu support
     */
    protected class PopupGraphMousePlugin extends AbstractPopupGraphMousePlugin {

        private Forest<Integer, Integer> tempTreeToCopy = null;
        Integer tempRoot = null;

        public PopupGraphMousePlugin() {
            this(MouseEvent.BUTTON3_MASK);
        }

        public PopupGraphMousePlugin(int modifiers) {
            super(modifiers);
        }

        @SuppressWarnings("unchecked")
        protected void handlePopup(MouseEvent e) {
            Point2D p = e.getPoint();
            GraphElementAccessor<Integer, Integer> pickSupport = vv.getPickSupport();
            if (pickSupport != null) {
                final Integer v = pickSupport.getVertex(vv.getGraphLayout(), p.getX(), p.getY());
                final AbstractAction pasteButton = new AbstractAction("Paste complete subtree") {

                    public void actionPerformed(ActionEvent e) {
                        /**
                         * Setting up selected root children
                         */
                        if (tempTreeToCopy != null) {
                            Collection<Integer> cl = tempTreeToCopy.getChildren(tempRoot);
                            for (Integer n : cl) {
                                graph.addEdge(nodeCounter_, v, nodeCounter_, EdgeType.DIRECTED);
                                
                                
                                logicalTree_.getNodeAt(v).addChild(new MyNode(new Agent(nodeCounter_)));

                                Agent agentToSet = (Agent) logicalTree_.getNodeAt(nodeCounter_).getData();

                                AgentType tempType = (AgentType) logicalTree_.getNodeAt(n).getData().getType();
                                if (tempType != null) {
                                    agentToSet.setType(tempType);
                                    typeAssaingedCollection_.add(nodeCounter_);
                                }
                                Map<String, Double> tempMap = logicalTree_.getNodeAt(n).getData().getHappinessMap();
                                if (tempMap != null) {
                                    agentToSet.setHappinessMap(tempMap);
                                }
                                List<Operator> tempList = logicalTree_.getNodeAt(n).getData().getOperatorsList();
                                if (tempList != null) {
                                    agentToSet.setOperatorsList(tempList);
                                }
                                Agent tempAgent = (Agent) logicalTree_.getNodeAt(n).getData();
                                if (tempAgent.isMultilpe()) {
                                    agentToSet.setMultipleMode(tempAgent.getNumberOfInstances());
                                    agentToSet.setInstacesHappMap(tempAgent.getInstacesHappMap());
                                }
                                nodeCounter_++;
                            }
                            /*
                             * Setting up selected root - already in the tree
                             */
                            Agent agentToSet = (Agent) logicalTree_.getNodeAt(v).getData();
                            AgentType tempType = (AgentType) logicalTree_.getNodeAt(tempRoot).getData().getType();
                            if (tempType != null) {
                                agentToSet.setType(tempType);
                                typeAssaingedCollection_.add(v);
                            }
                            Map<String, Double> tempMap = logicalTree_.getNodeAt(tempRoot).getData().getHappinessMap();
                            if (tempMap != null) {
                                agentToSet.setHappinessMap(tempMap);
                            }
                            
//                            List<Operator> tempList = logicalTree_.getNodeAt(tempRoot).getData().getOperatorsList();
//                            if (tempList != null) {
//                                agentToSet.setOperatorsList(tempList);
//                            }

                            layout = new TreeLayout<Integer, Integer>(graph, 70, 80);
                            vv.setGraphLayout(layout);
                            vv.repaint();
                            tempTreeToCopy = null;
                        }
                    }
                };

                if (v != null) {
                    JPopupMenu popup = new JPopupMenu();
                    popup.add(new AbstractAction("Deselect branch") {

                        public void actionPerformed(ActionEvent e) {
                            try {
                                Forest<Integer, Integer> tempTree = TreeUtils.getSubTree(graph, v);
                                for (Integer i : tempTree.getVertices()) {
                                    if (!deselectedCollection_.contains(i)) {
                                        deselectedCollection_.add(i);
                                    }
                                }
                            } catch (InstantiationException s) {
                            } catch (IllegalAccessException w) {
                            }
                            vv.repaint();
                        }
                    });
                    popup.add(new AbstractAction("Reselect branch") {

                        public void actionPerformed(ActionEvent e) {
                            try {
                                Forest<Integer, Integer> tempTree = TreeUtils.getSubTree(graph, v);
                                for (Integer i : tempTree.getVertices()) {
                                    deselectedCollection_.remove(i);
                                }
                            } catch (InstantiationException s) {
                            } catch (IllegalAccessException w) {
                            }
                            vv.repaint();
                        }
                    });
                    popup.add(new AbstractAction("Copy complete subtree") {

                        public void actionPerformed(ActionEvent e) {
                            try {
                                tempTreeToCopy = TreeUtils.getSubTree(graph, v);
                                tempRoot = v;
                                //    pasteButton.setEnabled(false);
                            } catch (InstantiationException s) {
                            } catch (IllegalAccessException w) {
                            }
                            vv.repaint();
                        }
                    });
                    popup.add(pasteButton);
                    popup.show(vv, e.getX(), e.getY());
                }
            }
        }
    }

    private class MyVertexFillPaintFunction<V> implements Transformer<V, Paint> {

        public Paint transform(V v) {
            if (deselectedCollection_.contains((Integer) v)) {
                return Color.LIGHT_GRAY;
            }
            if (picked_state.isPicked((Integer) v)) {
                return Color.YELLOW;
            } else if (typeAssaingedCollection_.contains((Integer) v)) {   
                return Color.GREEN;
            } else if (graph.getChildCount((Integer) v) == 0) {       
                return Color.orange;
            } else {
                return Color.RED;
            }
        }
    }

    private class ClusterVertexShapeFunction<V> extends EllipseVertexShapeTransformer<V> {

        ClusterVertexShapeFunction() {
            setSizeTransformer(new ClusterVertexSizeFunction<V>(20));
        }

        @SuppressWarnings("unchecked")
        @Override
        public Shape transform(V v) {
            if (multipleNodeCollection_.contains((Integer) v)) {
                return factory.getRegularStar(v, 5);
            }
            return super.transform(v);
        }
    }

    private class ClusterVertexSizeFunction<V> implements Transformer<V, Integer> {

        int size;

        public ClusterVertexSizeFunction(Integer size) {
            this.size = size;
        }

        public Integer transform(V v) {
            if (multipleNodeCollection_.contains((Integer) v)) {
                return 30;
            }
            return size;
        }
    }

    private class VertexTips<V> implements Transformer<V, String> {

        public String transform(V v) {
            StringBuilder sb = new StringBuilder();
            String s;
            Agent tempAgent = (Agent) logicalTree_.getNodeAt((Integer) v).getData();
            if (typeAssaingedCollection_.contains((Integer) v)) {             
                s = ("Type: " + tempAgent.getType().getAgentTypeName() + " ");
                sb.append(s);
            }
            if (multipleNodeCollection_.contains((Integer) v)) {              
                s = ("Mode: Multiple: " + tempAgent.getNumberOfInstances());
                sb.append(s);
            }
            sb.append("\n");
            if (tempAgent.getHappinessMap() != null) {
                DecimalFormat twoDForm = new DecimalFormat("#.###");
                sb.append(" Happiness levels : ");
                for (String happ : tempAgent.getHappinessMap().keySet()) {
                    sb.append(happ + " : ");
                    sb.append(twoDForm.format(tempAgent.getHappinessMap().get(happ)) + "   ");
                }
            }
            return sb.toString();
        }
    }
//     private class PickWithIconListener implements ItemListener {
//        DefaultVertexIconTransformer<Integer> imager;
//        Icon checked;
//        
//         public PickWithIconListener(DefaultVertexIconTransformer<Integer> imager) {
//             this.imager = imager;           
//               BufferedImage img = null;
//                try {
//                    img = ImageIO.read(new File("yellowball.png"));                   
//                } catch (IOException e) {
//                }
//                checked = new LayeredIcon(img.getScaledInstance(30, 30, Image.SCALE_SMOOTH));
//          // checked = new LayeredIcon(tempImage.getScaledInstance(20, 20, 0));
//         }
//
//        public void itemStateChanged(ItemEvent e) {
//            Icon icon = imager.transform((Integer) e.getItem());
//            if (icon != null && icon instanceof LayeredIcon) {
//                if (e.getStateChange() == ItemEvent.SELECTED) {
//                    ((LayeredIcon) icon).add(checked);
//                } else {
//                    ((LayeredIcon) icon).remove(checked);
//                }
//            }
//        }
//    }

    public class MyDefaultVertexIconTransformer<V> extends DefaultVertexIconTransformer<V> {

        private ArrayList<Color> c =null;
        @Override
        public void setIconMap(Map<V, Icon> iconMap) {
            super.setIconMap(iconMap);
        }
        @Override
        public Icon transform(V v) {
            // super.transform(v);   
            if (deselectedCollection_.contains((Integer) v)) {
                return null;
            }
            if (picked_state.isPicked((Integer) v)) {
                return setIcon(v,yellowImageIcon);
            } else if (typeAssaingedCollection_.contains((Integer) v) &&
                    (boolean) logicalTree_.getNodeAt((Integer) v).getData().isMultilpe() )  {
                return setIcon(v,greenImageIconM);               
            } else if (typeAssaingedCollection_.contains((Integer) v)) {
                return setIcon(v,greenImageIcon);               
            } else if (graph.getChildCount((Integer) v) == 0 &&
                    (boolean) logicalTree_.getNodeAt((Integer) v).getData().isMultilpe()) {
                return setIcon(v,orangeImageIconM);
            } else if (graph.getChildCount((Integer) v) == 0) {
                return setIcon(v,orangeImageIcon);
            } else {
                return setIcon(v,redImageIcon);
            }
        }

        private Icon initVertexIndicator(V v) {
            Color[] colorTab = {Color.RED, Color.blue,Color.PINK, Color.CYAN, Color.BLACK, Color.ORANGE, Color.MAGENTA};
            Agent tempAgent = (Agent) logicalTree_.getNodeAt((Integer) v).getData();
            if (tempAgent.getHappinessMap() != null) {
                int goalsCount = tempAgent.getType().getGoalsList().size();
                tempImage = new BufferedImage(100, 200, BufferedImage.TYPE_INT_ARGB);
                Graphics2D g2d = tempImage.createGraphics();
                Color myColor = new Color(Color.white.getRGB(), true);
                g2d.setPaint(myColor);
                int height = 75;
                g2d.drawRect(0, 0, 100 - 1, 200 - 1);
                //int bb =(100 * goalsCount)/2;
                int bb = 50;
                //  int width = bb/goalsCount;
                int width = 10;
                for (String goalName : tempAgent.getType().getGoalsList()) {
                    Double d = tempAgent.getHappinessMap().get(goalName);
                    int newHeight = (int) (d * height);
                    g2d.setPaint(colorTab[(Integer)v%colorTab.length]);
                    g2d.fillRect(bb, 1 + (height - newHeight), width - 1, newHeight);
                    g2d.setPaint(Color.BLACK);
                    g2d.drawRect(bb, 1, width - 1, height);
                    bb += width;
                }
                Icon extra = this.getIconMap().get(v);
                ((LayeredIcon) extra).add(new LayeredIcon(tempImage.getScaledInstance(70, 100, Image.SCALE_SMOOTH)));
                return extra;
            }
            if(tempAgent.getInstacesHappMap()!=null) {
                return this.getIconMap().get(v);
            }
            return null;
        }

        private Color randColor(V v) {
            Color[] colorTab = {Color.RED, Color.blue, Color.CYAN, Color.GREEN, Color.ORANGE};
            Random gen = new Random();
            int i = gen.nextInt(colorTab.length);
            Color choosen = colorTab[i];
            return choosen;
        }

        private Icon setIcon(V v, BufferedImage imageIcon) {
                Icon icon = new LayeredIcon(imageIcon.getScaledInstance(25, 25, Image.SCALE_SMOOTH));
                this.getIconMap().put(v, icon);
                return initVertexIndicator(v);
             //   Icon temp = null;
        }
    }
}